package timing.ukulele.seal.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.io.IOUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import timing.ukulele.http.OkHttpManager;
import timing.ukulele.persistence.service.BaseService;
import timing.ukulele.seal.mapper.SealMapper;
import timing.ukulele.seal.persistent.Seal;
import timing.ukulele.seal.service.minio.BucketService;
import timing.ukulele.seal.service.minio.ObjectService;
import timing.ukulele.seal.vo.SealVO;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

import static timing.ukulele.seal.config.TopicConfig.SEAL_CROP_CHANNEL;
import static timing.ukulele.seal.config.TopicConfig.SEAL_CROP_ROUTING;

@Service
public class SealService extends BaseService<SealMapper, Seal> {
    public static final String SEAL_BUCKET = "seal";
    private final ObjectService objectService;
    private final BucketService bucketService;
    private final AmqpTemplate rabbitTemplate;

    @Value("${ukulele.crop.url}")
    private String cropUrl;

    public SealService(ObjectService objectService, BucketService bucketService, AmqpTemplate rabbitTemplate) {
        this.objectService = objectService;
        this.bucketService = bucketService;
        this.rabbitTemplate = rabbitTemplate;
    }

    public IPage<SealVO> getPage(String name, Integer type, int current, int size) {
        Page<Seal> page = new Page<>(current, size);
        QueryWrapper<Seal> wrapper = new QueryWrapper<>();
        wrapper.lambda().orderByDesc(Seal::getId);
        if (StringUtils.hasText(name)) {
            wrapper.lambda().like(Seal::getName, name);
        }
        if (type != null) {
            wrapper.lambda().eq(Seal::getType, type);
        }
        Page<Seal> iPage = this.baseMapper.selectPage(page, wrapper);
        Page<SealVO> voPage = new Page<>(current, size);
        if (iPage != null && !CollectionUtils.isEmpty(iPage.getRecords())) {
            List<SealVO> voList = new ArrayList<>(iPage.getRecords().size());
            iPage.getRecords().forEach(po -> {
                SealVO vo = new SealVO();
                BeanUtils.copyProperties(po, vo);
                voList.add(vo);
            });
            voPage.setRecords(voList);
            voPage.setTotal(iPage.getTotal());
            voPage.setOrders(iPage.orders());
        }
        return voPage;
    }

    public boolean delete(Long id) throws Exception {
        Seal seal = getById(id);
        if (seal == null)
            return true;
        if (StringUtils.hasText(seal.getSealFile()))
            objectService.removeObject(SEAL_BUCKET, seal.getSealFile());
        removeById(id);
        return true;
    }

    public void setCropSeal(Seal seal) {
        if (seal == null || seal.getId() == null || StringUtils.isEmpty(seal.getSealFile()))
            return;
        try {
            InputStream object = objectService.getObject(SEAL_BUCKET, seal.getSealFile());
            if (object != null) {
                okhttp3.RequestBody body = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM)
                        .addFormDataPart("file", seal.getSealFile().substring(seal.getSealFile().lastIndexOf("/") + 1),
                                okhttp3.RequestBody.create(MediaType.parse("multipart/form-data"), toByteArray(object))).build();
                Request request = new Request.Builder()
                        .url(cropUrl).post(body)
                        .build();
                String newName = seal.getSealFile().replace(".", "-") + ".png";
                Response result = OkHttpManager.INSTANCE.build(null).getClient().newCall(request).execute();
                if (result.isSuccessful() && result.body() != null) {
                    objectService.putObject(SEAL_BUCKET, newName, result.body().byteStream(), "image/png");
                }
                lambdaUpdate().set(Seal::getSealFile, newName).eq(Seal::getId, seal.getId()).update();
                object.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }

    public void setSealFile(Seal seal, MultipartFile file) throws Exception {
        if (!bucketService.bucketExists(SEAL_BUCKET))
            bucketService.makeBucket(SEAL_BUCKET);
        // 先删除之前的印章
        if (StringUtils.hasText(seal.getSealFile()))
            objectService.removeObject(SEAL_BUCKET, seal.getSealFile());
        String objectName = UUID.randomUUID() + Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."));
        objectService.putObject(SEAL_BUCKET, objectName, file.getInputStream(), file.getContentType());
        lambdaUpdate().set(Seal::getSealFile, objectName)
                .set(Seal::getUpdateBy, seal.getUpdateBy())
                .set(Seal::getUpdateTime, new Date())
                .eq(Seal::getId, seal.getId()).update();
        seal.setSealFile(objectName);
        rabbitTemplate.convertAndSend(SEAL_CROP_CHANNEL, SEAL_CROP_ROUTING, seal);
    }

    public void getSeal(Seal seal, HttpServletResponse response) {
//        response.setCharacterEncoding("UTF-8");
        // 清空response
        response.reset();
        response.setContentType("image/png");
        response.setHeader("Content-Disposition", "attachment;filename=seal.png");
        try (ServletOutputStream out = response.getOutputStream()) {
            InputStream object = objectService.getObject(SEAL_BUCKET, seal.getSealFile());
            // 添加水印
            InputStream ins = SealService.class.getClassLoader().getResourceAsStream("watermark.png");
            if (ins == null)
                return;
            Thumbnails.of(object).scale(1.0d).watermark(ImageIO.read(ins)).toOutputStream(out);
            out.flush();
            object.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ByteArrayOutputStream getSeal(Seal seal) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            InputStream object = objectService.getObject(SEAL_BUCKET, seal.getSealFile());
            IOUtils.copy(object, out);
            object.close();
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
